﻿using System;

namespace POBR.ImageProcessor
{
	/*
	 * NOTE:
	 * 1. The order of values in Pixels array is as follows:
	 *	  blue, green, red, alpha
	 *	  All the methods take / return values in RGB format, so the coordinates should be mapped.
	 * 2. The (0, 0) point in Pixels array is positioned at the top-left corner.
	 *    All the (0, 0) point of the Picture should be bottom-left corner, so the y coordinate needs invertion.
	 */
	public class Picture
	{
		public int Width { get; private set; }
		public int Height { get; private set; }
		public byte[] Pixels { get; private set; }

		public Picture(int width, int height, byte[] pixels)
		{
			Width = width;
			Height = height;
			Pixels = pixels;
		}

		public Picture Clone()
		{
			var pixels = new byte[Pixels.Length];

			for (int i = 0; i != Pixels.Length; ++i)
				pixels[i] = Pixels[i];

			return new Picture(Width, Height, pixels);
		}

		private int GetOffset(int x, int y)
		{
			return (y * Width + x) * 4;
		}

		#region Get methods

		public byte[] GetPixel(int x, int y)
		{
			var offset = GetOffset(x, y);

			return new[] { Pixels[offset + 2], Pixels[offset + 1], Pixels[offset] };
		}

		public byte GetR(int x, int y)
		{
			return GetPixel(x, y)[0];
		}

		public byte GetG(int x, int y)
		{
			return GetPixel(x, y)[1];
		}

		public byte GetB(int x, int y)
		{
			return GetPixel(x, y)[2];
		}

		#endregion

		#region Set methods

		public void SetPixel(int x, int y, byte r, byte g, byte b)
		{
			SetPixel(x, y, new[] { r, g, b });
		}

		public void SetPixel(int x, int y, byte[] pixel)
		{
			if (pixel.Length != 3)
				throw new ArgumentException("Pixel must have 3 values.");

			var offset = (y * Width + x) * 4;
			Pixels[offset + 2] = pixel[0];
			Pixels[offset + 1] = pixel[1];
			Pixels[offset] = pixel[2];
		}

		public void SetR(int x, int y, byte value)
		{
			var position = GetOffset(x, y) + 2;
			Pixels[position] = value;
		}

		public void SetG(int x, int y, byte value)
		{
			var position = GetOffset(x, y) + 1;
			Pixels[position] = value;
		}

		public void SetB(int x, int y, byte value)
		{
			var position = GetOffset(x, y);
			Pixels[position] = value;
		}

		public void SetBlack(int x, int y)
		{
			SetPixel(x, y, 0, 0, 0);
		}

		public void SetWhite(int x, int y)
		{
			SetPixel(x, y, 255, 255, 255);
		}

		public void SetRed(int x, int y)
		{
			SetPixel(x, y, 255, 0, 0);
		}
		public void SetGreen(int x, int y)
		{
			SetPixel(x, y, 0, 255, 0);
		}
		public void SetBlue(int x, int y)
		{
			SetPixel(x, y, 0, 0, 255);
		}
		
		#endregion

		#region Bool methods

		public bool IsBlack(int x, int y)
		{
			var pixel = GetPixel(x, y);

			return pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0;
		}

		public bool IsWhite(int x, int y)
		{
			var pixel = GetPixel(x, y);

			return pixel[0] == 255 && pixel[1] == 255 && pixel[2] == 255;
		}

		public bool IsRed(int x, int y)
		{
			var pixel = GetPixel(x, y);

			return pixel[0] == 255 && pixel[1] == 0 && pixel[2] == 0;
		}

		public bool IsGreen(int x, int y)
		{
			var pixel = GetPixel(x, y);

			return pixel[0] == 0 && pixel[1] == 255 && pixel[2] == 0;
		}

		public bool IsBlue(int x, int y)
		{
			var pixel = GetPixel(x, y);

			return pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 255;
		}

		#endregion
	}
}
